#include "Codec.h"
#include <string.h>

unsigned long encodeLong(unsigned long src, char *dst) {
	unsigned long srcTmp = 0;

	if (dst == NULL) {
		return sizeof(unsigned long);
	}
	srcTmp = htonl(src);
	memcpy(dst, &srcTmp, sizeof(unsigned long));
	return sizeof(unsigned long);
}

unsigned long decodeLong(char *src, unsigned long *dst) {
	unsigned long srcTmp = 0;
	if (src == NULL)
		return -1;
	if (dst == NULL)
		return sizeof(unsigned long);

	memcpy(&srcTmp, src, sizeof(unsigned long));
	*dst = ntohl(srcTmp);
	return sizeof(unsigned long);
}

char *encode_PacketHeader(PACKET_HEADER *head, unsigned long *length) {
	unsigned long nm = 0;
	char *buffer;
	*length = 0;
	*length += encodeLong(head->protocol, NULL);
	*length += encodeLong(head->msgType, NULL);
	*length += encodeLong(head->dataLength, NULL);
	*length += encodeLong(head->reserved, NULL);

	buffer = (char *) calloc(*length, sizeof(char));

	nm += encodeLong(head->protocol, buffer);
	nm += encodeLong(head->msgType, buffer + nm);
	nm += encodeLong(head->dataLength, buffer + nm);
	nm += encodeLong(head->reserved, buffer + nm);
	return buffer;
}
PACKET_HEADER *decode_PacketHeader(char *buf, unsigned long *length) {
	PACKET_HEADER *head;
	unsigned long protocol = 0;
	unsigned long msgType = 0;
	unsigned long dataLength = 0;
	unsigned long reserved = 0;

	*length = 0;
	*length += decodeLong(buf, &protocol);
	*length += decodeLong(buf + *length, &msgType);
	*length += decodeLong(buf + *length, &dataLength);
	*length += decodeLong(buf + *length, &reserved);

	head = initPacketHeader(protocol, msgType, dataLength);

	return head;
}
char *encode_MSG_LOGIN_REQ_DATA(PACKET_DATA *data, unsigned long *length) {
	char *buffer;
	MSG_LOGIN_REQ_DATA *req = (MSG_LOGIN_REQ_DATA *) data;
	*length = 32;
	buffer = (char *) calloc(*length, sizeof(char));
	memcpy(buffer, req->id, 16);
	memcpy(buffer, req->pwd, 16);
	return buffer;
}
PACKET_DATA *decode_MSG_LOGIN_REQ_DATA(char *buf, unsigned long *length) {
	MSG_LOGIN_REQ_DATA *data;
	*length = 32;
	data = (MSG_LOGIN_REQ_DATA *) init_MSG_LOGIN_REQ_DATA(buf);
	return (PACKET_DATA *) data;
}
PACKET_DATA *decode_MSG_LOGIN_ACK_DATA(char *buf, unsigned long *length) {
	MSG_LOGIN_ACK_DATA *data;
	*length = 10;
	data = (MSG_LOGIN_ACK_DATA *) init_MSG_LOGIN_ACK_DATA(buf);
	return (PACKET_DATA *) data;
}
char *encode_MSG_LOGIN_ACK_DATA(PACKET_DATA *data, unsigned long *length) {
	char *buffer;
	MSG_LOGIN_ACK_DATA *req = (MSG_LOGIN_ACK_DATA *) data;
	*length = 10;
	buffer = (char *) calloc(*length, sizeof(char));
	memcpy(buffer, req->serverMessage, 10);
	return buffer;
}
char *encode_PacketData(PACKET_DATA *data, unsigned long *length,
		PACKET_HEADER *head) {
	switch (head->msgType) {
	case MSG_LOGIN_ACK:
		return encode_MSG_LOGIN_ACK_DATA(data, length);
	case MSG_LOGIN_REQ:
		return encode_MSG_LOGIN_REQ_DATA(data, length);
	}
	return NULL;
}
PACKET_DATA *decode_PacketData(char *buffer, unsigned long *length,
		PACKET_HEADER *head) {
	switch (head->msgType) {
	case MSG_LOGIN_REQ:
		return decode_MSG_LOGIN_REQ_DATA(buffer, length);
	case MSG_LOGIN_ACK:
		return decode_MSG_LOGIN_ACK_DATA(buffer, length);
	}
	return NULL;
}
char encode_Packet(PACKET *packet, unsigned long *length) {
	unsigned long headLength = 0, dataLength = 0;
	PACKET_HEADER *head = packet->header;
	char *headBuf = encode_PacketHeader(head, &headLength);
	PACKET_DATA *data = packet->data;
	char *dataBuf = encode_PacketData(data, &dataLength, head);
	*length = headLength + dataLength;
	char *packetBuf = (char *) calloc(*length, sizeof(char));
	memcpy(packetBuf, headBuf, headLength);
	memcpy(packetBuf + headLength, dataBuf, dataLength);
	free(headBuf);
	free(dataBuf);
	return packetBuf;
}
PACKET *decode_PACKET(char *buffer, unsigned long *length) {
	PACKET *packet = makeNewPacket();
	unsigned long headLength = 0, dataLength = 0;

	packet->header = decode_PacketHeader(buffer, &headLength);
	packet->data = decode_PacketData(buffer + headLength, &dataLength,
			packet->header);
	*length = headLength + dataLength;
	return packet;
}
